package com.netflexitysolutions.amazonws.sdb.orm.filter;

import com.netflexitysolutions.amazonws.sdb.orm.internal.util.QueryUtils;
import com.netflexitysolutions.amazonws.sdb.orm.internal.util.StringConstants;


/**
 * A Predicate that represents the AND, OR or XOR condition
 * on two other predicates.
 */

public class CompoundPredicate<T> extends Predicate<T> {

    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	public static final int UNION = 1;
    public static final int INTERSECTION = 2;

    final Predicate<T> lhs, rhs;
    final int operation;

    /**
     * @param operation
     * @param lhs
     * @param rhs
     */
    protected CompoundPredicate(int operation, Predicate<T> lhs, Predicate<T> rhs) {
        this.lhs = lhs;
        this.rhs = rhs;
        this.operation = operation;
        
        assert(operation == UNION || operation == INTERSECTION);
        assert(lhs.getType().equals(rhs.getType()));
    }

    /* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.sdb.orm.filter.Filter#filter(java.lang.Object)
	 */
	public boolean filter(T record) {
		switch (operation) {
	        case UNION:
	            return lhs.filter(record) || rhs.filter(record);
	        case INTERSECTION :
	            return lhs.filter(record) && rhs.filter(record);
		}
		return false;
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.sdb.orm.filter.Filter#getType()
	 */
	public Class<T> getType() {
		return lhs.getType();
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.sdb.orm.filter.Filter#toSelect()
	 */
	public String toSelect() {
        String conjunction = (operation == UNION) ? (StringConstants.RP + QueryUtils.OR + StringConstants.LP) : (StringConstants.RP + QueryUtils.AND + StringConstants.LP);
        String where1 = lhs.toSelect();
        String where2 = rhs.toSelect();
        if (where1 == null || where2 == null)
            return null;
        if (where1.equals(where2))
            return where1;
        return StringConstants.LP
            + where1
            + conjunction
            + where2
            + StringConstants.RP;
    }

    /* (non-Javadoc)
     * @see com.netflexitysolutions.amazonws.sdb.orm.filter.Predicate#getComplement()
     */
    public Predicate<T> getComplement() {
        if (complement == null) {
            switch (operation) {
                case UNION:
                    complement = new CompoundPredicate<T>(INTERSECTION, lhs.getComplement(), rhs.getComplement());
                    complement.complement = this;
                    break;
                case INTERSECTION :
                    complement = new CompoundPredicate<T>(UNION, lhs.getComplement(), rhs.getComplement());
                    complement.complement = this;
                    break;
            }
        }
        return complement;
    }
}
